#pragma once

#define FUNID(id)      \
    enum               \
    {                  \
        FUN_ID = id    \
    };                 \
    UINT GetID()       \
    {                  \
        return FUN_ID; \
    }

#define FUN_BEGIN                                     \
    bool HandleFun(UINT uMsg, SOUI::SParamStream &ps) \
    {                                                 \
        bool bHandled = false;

#define FUN_HANDLER(x, fun)                                        \
    if (!bHandled && uMsg == x::FUN_ID)                            \
    {                                                              \
        x param;                                                   \
        GetIpcHandle()->FromStream4Input(&param, ps.GetBuffer());  \
        DWORD dwPos = ps.GetBuffer()->Tell();                      \
        fun(param);                                                \
        ps.GetBuffer()->Seek(SOUI::IShareBuffer::seek_set, dwPos); \
        GetIpcHandle()->ToStream4Output(&param, ps.GetBuffer());   \
        bHandled = true;                                           \
    }

#define FUN_END      \
    return bHandled; \
    }

#define CHAIN_MSG_MAP_2_IPC(ipc)                                                     \
    if (ipc)                                                                         \
    {                                                                                \
        BOOL bHandled = FALSE;                                                       \
        lResult = (ipc)->OnMessage((ULONG_PTR)hWnd, uMsg, wParam, lParam, bHandled); \
        if (bHandled)                                                                \
        {                                                                            \
            return true;                                                             \
        }                                                                            \
    }

/////////////////////////////////////////////////////////////////////
template <typename P1>
void toParamStream(SOUI::SParamStream &ps, P1 &p1)
{
    ps << p1;
}
template <typename P1>
void fromParamStream(SOUI::SParamStream &ps, P1 &p1)
{
    ps >> p1;
}

#define PARAMS1(type, p1)                          \
    void ToStream4##type(SOUI::SParamStream &ps)   \
    {                                              \
        toParamStream(ps, p1);                     \
    }                                              \
    void FromStream4##type(SOUI::SParamStream &ps) \
    {                                              \
        fromParamStream(ps, p1);                   \
    }

/////////////////////////////////////////////////////////////
template <typename P1, typename P2>
void toParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2)
{
    ps << p1 << p2;
}
template <typename P1, typename P2>
void fromParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2)
{
    ps >> p1 >> p2;
}

#define PARAMS2(type, p1, p2)                      \
    void ToStream4##type(SOUI::SParamStream &ps)   \
    {                                              \
        toParamStream(ps, p1, p2);                 \
    }                                              \
    void FromStream4##type(SOUI::SParamStream &ps) \
    {                                              \
        fromParamStream(ps, p1, p2);               \
    }

////////////////////////////////////////////////////////////////////
template <typename P1, typename P2, typename P3>
void toParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3)
{
    ps << p1 << p2 << p3;
}
template <typename P1, typename P2, typename P3>
void fromParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3)
{
    ps >> p1 >> p2 >> p3;
}

#define PARAMS3(type, p1, p2, p3)                  \
    void ToStream4##type(SOUI::SParamStream &ps)   \
    {                                              \
        toParamStream(ps, p1, p2, p3);             \
    }                                              \
    void FromStream4##type(SOUI::SParamStream &ps) \
    {                                              \
        fromParamStream(ps, p1, p2, p3);           \
    }

///////////////////////////////////////////////////////////////////
template <typename P1, typename P2, typename P3, typename P4>
void toParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3, P4 &p4)
{
    ps << p1 << p2 << p3 << p4;
}
template <typename P1, typename P2, typename P3, typename P4>
void fromParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3, P4 &p4)
{
    ps >> p1 >> p2 >> p3 >> p4;
}

#define PARAMS4(type, p1, p2, p3, p4)              \
    void ToStream4##type(SOUI::SParamStream &ps)   \
    {                                              \
        toParamStream(ps, p1, p2, p3, p4);         \
    }                                              \
    void FromStream4##type(SOUI::SParamStream &ps) \
    {                                              \
        fromParamStream(ps, p1, p2, p3, p4);       \
    }

/////////////////////////////////////////////////////////////////////////
template <typename P1, typename P2, typename P3, typename P4, typename P5>
void toParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5)
{
    ps << p1 << p2 << p3 << p4 << p5;
}
template <typename P1, typename P2, typename P3, typename P4, typename P5>
void fromParamStream(SOUI::SParamStream &ps, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5)
{
    ps >> p1 >> p2 >> p3 >> p4 >> p5;
}

#define PARAMS5(type, p1, p2, p3, p4, p5)          \
    void ToStream4##type(SOUI::SParamStream &ps)   \
    {                                              \
        toParamStream(ps, p1, p2, p3, p4, p5);     \
    }                                              \
    void FromStream4##type(SOUI::SParamStream &ps) \
    {                                              \
        fromParamStream(ps, p1, p2, p3, p4, p5);   \
    }
